#include <QtCore/QDebug>
#include <QtGui/QPainter>

#include "areadetectionmodel.h"

AreaDetectionTask::AreaDetectionTask(AreaDetectionModel& model, QObject *parent)
    : BackgroundTask(QString(tr("Area detection")), parent),
    _model(model)
{

}

void AreaDetectionTask::doRun()
{
    int thresholdValue = _model.thresholdValue();
    GrayscaleImage image = _model.sourceImage();
    QSize size = image.size();
    BinaryImage detectAreaImage = BinaryImage(size);
    progressRangeChanged(0, size.height());
    for( int row = 0; row < size.height(); row++ ) {
        for ( int col = 0; col < size.width(); col++ ) {
            Grayscale pixel = image.grayscale(col, row);
            if (pixel < thresholdValue) {
                detectAreaImage.setBinaryColor(col, row, White);
            }
            else {
                detectAreaImage.setBinaryColor(col, row, Black);
            }
            if (_isCanceled) {
                return;
            }
        }
        progressValueChanged(row);
    }
    _model.setDetectedAreasImage(detectAreaImage);
}

void AreaDetectionTask::doCancel()
{

}

ComputeHistogramTask::ComputeHistogramTask(AreaDetectionModel& model, QObject *parent)
    : BackgroundTask(QString("Histogram computation"), parent),
    _model(model)
{

}

void ComputeHistogramTask::doRun()
{
    QVector<int> histogramData;
    histogramData.fill(0, GRAYSCALE_COLOR_RANGE); // TODO move to GrayscaleImage
    for (int i = 0; i < histogramData.size(); i++) {
        histogramData[i] = 0;
    }
    GrayscaleImage image = _model.sourceImage();
    QSize size = image.size();
    emit progressRangeChanged(0, size.height());
    for( int row = 0; row < size.height(); row++ ) {
        for ( int col = 0; col < size.width(); col++ ) {
            Grayscale pixel = image.grayscale(col, row);
            int index = pixel; // TODO type
            histogramData[index]++; // TODO type
            if (_isCanceled) {
                return;
            }
        }
        emit progressValueChanged(row);
    }
    _model.setHistogramData(histogramData);
    _model.computeThresholdValue();
    _model.updateHistogram();
}

void ComputeHistogramTask::doCancel()
{

}

AreaDetectionModel::AreaDetectionModel(QObject *parent)
    : ImageModel(parent),
    _histogramData(),
    _thresholdValue(DEFAULT_THRESHOLD_VALUE)
{

}

void AreaDetectionModel::setSourceImage(const GrayscaleImage& image)
{    
    setFeature(ESourceImage, 0, qVariantFromValue(image));
    setFeature(EHistogramImage, 0, qVariantFromValue(ColorImage()));
    setFeature(EDetectedAreasImage, 0, qVariantFromValue(BinaryImage()));
    _thresholdValue = DEFAULT_THRESHOLD_VALUE;
    _histogramData.clear();
}

GrayscaleImage AreaDetectionModel::sourceImage()
{         
    return qVariantValue<GrayscaleImage>(feature(ESourceImage, 0));
}

ComputeHistogramTask* AreaDetectionModel::computeHistogram()
{    
    return new ComputeHistogramTask(*this);
}

void AreaDetectionModel::setHistogramData(const QVector<int> &data)
{
    _histogramData.clear();
    _histogramData = data;
}

void AreaDetectionModel::setHistogramImage(const ColorImage &image)
{
    setFeature(EHistogramImage, 0, qVariantFromValue(image));
}

ColorImage AreaDetectionModel::histogramImage()
{
    return qVariantValue<ColorImage>(feature(EHistogramImage, 0));
}

void AreaDetectionModel::updateHistogram()
{   
    ColorImage histogramImage = this->histogramImage();
    if ( !_histogramData.isEmpty() && histogramImage.isNull()) {
        int max = 0;
        for (int i = 0; i < _histogramData.size(); i++) {
            if (max < _histogramData[i]) {
                max = _histogramData[i];
            }
        }        
        histogramImage = ColorImage(QSize(GRAYSCALE_COLOR_RANGE, max));
        QPainter painter(&histogramImage);        
        painter.setPen(QPen(Qt::red, 1, Qt::SolidLine, Qt::SquareCap));
        for (int x = 0; x < _histogramData.size(); x++) {
            int y = _histogramData[x];
            painter.drawLine(x, max, x, max-y);
        }
        painter.end();
        setHistogramImage(histogramImage);
    }    
    if (!histogramImage.isNull()) {
        ColorImage image;
        image = histogramImage.copy(); // TODO
        QPainter painterLine(&image);
        painterLine.setPen(QPen(Qt::black, 2, Qt::SolidLine, Qt::SquareCap));
        painterLine.drawLine(_thresholdValue, 0, _thresholdValue, histogramImage.height());
        painterLine.end();
        QSize size = sourceImage().size();
        image = image.scaled(size);
        setFeature(EHistogramImageWithThreshold, 0, image);
    }    
}

AreaDetectionTask* AreaDetectionModel::detectAreas()
{
    return new AreaDetectionTask(*this);
}

void AreaDetectionModel::setDetectedAreasImage(const BinaryImage &image)
{
    setFeature(EDetectedAreasImage, 0, qVariantFromValue(image));
    emit areasDetected(image);
}

BinaryImage AreaDetectionModel::detectedAreasImage()
{
    return qVariantValue<BinaryImage>(feature(EDetectedAreasImage, 0));
}

void AreaDetectionModel::computeThresholdValue()
{
    int min = GRAYSCALE_COLOR_RANGE;
    for (int i = 1; i < _histogramData.size()-1; i++) {
        int value = _histogramData[i];
        int before = _histogramData[i-1];
        int after = _histogramData[i+1];
        if (before >= value && after >= value) {
            if (value > 0 && value < min) {
                min = i;
            }
        }
    }
    _thresholdValue = min;
    emit thresholdValueChanged(_thresholdValue);    
}

int AreaDetectionModel::thresholdValue() const
{
    return _thresholdValue;
}

void AreaDetectionModel::setThresholdValue(int value) 
{
    if (_thresholdValue != value) {
        _thresholdValue = value;
        updateHistogram();
        emit thresholdValueChanged(_thresholdValue);
    }
}
